package org.springblade.dev.support;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.converts.MySqlTypeConvert;
import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
import com.baomidou.mybatisplus.generator.query.SQLQuery;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springblade.dev.constant.DevelopConstant;
import org.springblade.dev.template.BaseGenerator;
import org.springblade.dev.template.BootGenerator;
import org.springblade.dev.template.CloudGenerator;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;

import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * 保留版权 : CopyRright(C) 蛀虫
 * 文件名称 : DevelopApplication.java
 * 文件编号 : 1-1-1
 * 功能描述 : mp生成器
 * 文件版本 : 2021.06.23.01
 * 创建人名 : 于继业
 * 创建日期 : 2021-06-23
 * 修改人名 :
 * 修改日期 :
 * 【目前TableInfo和TableFields 是否没有表字段的是否为空，字段长度等信息？】https://github.com/baomidou/mybatis-plus/issues/1336
 * 【MyBatis-Plus代码生成器，如何自定义代码生成路径】https://blog.csdn.net/qq_29550537/article/details/105477585
 *
 * @author 于继业
 */
@Data
@Slf4j
public class BladeCodeGenerator {
    /**
     * 代码所在系统
     */
    private String systemName;
    /**
     * 代码模块名称
     */
    private String codeName;
    /**
     * 代码所在服务名
     */
    private String serviceName = "blade-service";
    /**
     * 代码生成的包名
     */
    private String packageName = "org.springblade.test";
    /**
     * 代码后端生成的地址
     */
    private String packageDir;
    /**
     * 代码前端生成的地址
     */
    private String packageWebDir;
    /**
     * 需要去掉的表前缀
     */
    private String tablePrefix = "blade_";
    /**
     * 需要生成的表名(两者只能取其一)
     */
    private List<String> includeTables = ListUtil.toList("blade_test");
    /**
     * 需要排除的表名(两者只能取其一)
     */
    private String[] excludeTables = {};
    /**
     * 是否包含基础业务字段
     */
    private Boolean hasSuperEntity = Boolean.FALSE;
    /**
     * 是否包含包装器
     */
    private Boolean hasWrapper = Boolean.FALSE;
    /**
     * 基础业务字段
     */
    private String[] superEntityColumns = {"id", "create_time", "create_user", "create_dept", "update_time", "update_user", "status", "is_deleted"};
    /* 项目路径 */
    private String projectPath;
    /*生成boot文件*/
    private boolean isBoot = Boolean.TRUE;

    public void run() {
        // 获取属性
        Properties props = getProperties();
        // 初始化生成器
        BaseGenerator baseGenerator = isBoot ? new BootGenerator() : new CloudGenerator();
        // 全局配置
        GlobalConfig config = baseGenerator.globalConfig(projectPath, props);
        // 包名配置
        PackageConfig packageConfig = baseGenerator.packageConfig(serviceName);
        // 模板配置(TemplateConfig)
        TemplateConfig templateConfig = baseGenerator.templateConfig();

        // 模板属性
        Map<String, Object> map = MapUtil.newHashMap();
        map.put("codeName", codeName);
        map.put("serviceName", serviceName);
        map.put("hasWrapper", hasWrapper);
        // 注入配置(InjectionConfig)
        InjectionConfig injectionConfig = baseGenerator.injectionConfig(map, packageWebDir, serviceName);

        // 策略配置
        StrategyConfig strategyConfig = baseGenerator.strategyConfig(tablePrefix, includeTables, superEntityColumns);

        // 数据源配置
        DataSourceConfig dataSourceConfig = this.dataSourceConfig(props);

        // 创建代码生成器对象，加载配置
        AutoGenerator autoGenerator = new AutoGenerator(dataSourceConfig);
        autoGenerator.global(config);
        autoGenerator.injection(injectionConfig);
        autoGenerator.template(templateConfig);
        autoGenerator.packageInfo(packageConfig);
        autoGenerator.strategy(strategyConfig);

        // 执行
        autoGenerator.execute();
    }

    /**
     * 获取配置文件
     *
     * @return 配置Props
     */
    @SneakyThrows
    private Properties getProperties() {
        // 读取配置文件
        Resource resource = new ClassPathResource("/code.properties");
        return PropertiesLoaderUtils.loadProperties(resource);
    }

    /**
     * 配置数据源
     *
     * @param props 属性文件
     * @return {@link DataSourceConfig}
     */
    public DataSourceConfig dataSourceConfig(Properties props) {
        // 数据源配置
        DataSourceConfig.Builder dataSourceConfigBuilder = new DataSourceConfig.Builder(
                props.getProperty("spring.datasource.url"),
                props.getProperty("spring.datasource.username"),
                props.getProperty("spring.datasource.password")
        );
        // 类型转换
        dataSourceConfigBuilder.typeConvert(new MySqlTypeConvert() {
            @Override
            public IColumnType processTypeConvert(GlobalConfig globalConfig, String tableField) {
                if (tableField.toLowerCase().contains("date") || tableField.toLowerCase().contains("timestamp") || tableField.toLowerCase().contains("datetime")) {
                    return DbColumnType.LOCAL_DATE;
                }
                return super.processTypeConvert(globalConfig, tableField);
            }
        });

        // 默认DefaultQuery.class(通用元数据), SQLQuery.class(SQL查询)
        dataSourceConfigBuilder.databaseQueryClass(SQLQuery.class);
        // 自定义查询必须 new MySqlQuery(),只在SQLQuery下生效
        dataSourceConfigBuilder.dbQuery(new CusMySqlQuery());
        // 需要设定tableschema ，否则活查出多个重复的字段
        dataSourceConfigBuilder.schema(DevelopConstant.TABLE_SCHEMA);
        return dataSourceConfigBuilder.build();
    }
}
